classdef globals_dev < handle
  % Broadly-used (in moorings-related code) parameters & functions
  % Derived from handle
  % C-tor sig: globs = globals_dev(config_file, t_interval, switches, sites, logFile);
  %                       all but first argument are optional
  %     config_file: path of configuration file containing default values;
  %                       may be empty
  %     t_interval:  time interval to process
  %     switches:    flow control switches
  %     sites:       mooring stations to process
  %        See rt_driver help, Usage section for more information on 
  %            t_interval, switches, and sites format requirements.
  %     logFile: file ID of open log file
  %
  % Author: David Goldsmith, Wash. State Dept. of Ecology, dgol461@ecy.wa.gov
  % Release date: < 9/15/2011
  
    properties 
      % Primary "movers & shakers"
        t_interval; 
        siteIDs = {};
        siteID = '';
        switches = struct();
        doDO;
        DB = '';
      % I/O stuff
        homeDir; 
        oEN; % error notification object;
        ftp_obj;
        web_obj;
        ftp_server = 'www.ecy.wa.gov';
        web_server = 'ecywblcyadfp01.ecy.wa.lcl';
        ftp_closed = true;
        web_closed = true;
        ftp_failure = false;
        web_failure = false;
        tag = '';
        fatal_error = false;
        subj = '';
        logFile;
      % Miscellany        
        MS2MATLAB_DTOFFSET = 693960; % Difference between MATLAB's and Microsoft's sdn's; 
                                     % necessary because the database server is a Microsoft product.
        av_win = [];
        av_thresh = [];
    end
    
    methods
        function globs = globals_dev(...
                            config_file,...
                            t_interval,...
                            switches,...
                            sites,...
                            logFile)
            import System.*
            import System.DateTime.*
            globs.homeDir = pwd;
            if nargin > 4
                globs.logFile = logFile;
            else
                globs.logFile = '';
            end
            if globs.logFile
                globals_dev.log_progress(globs,...
                                    ['Entered globals constructor, imported System.* and '...
                                    'SystemDateTime.*, and set \nglobals.logFile = %s\n'...
                                    'and globals.homeDir = %s\n'],...
                                    {which('rt_logfile.txt'), pwd});
            end
            
            if ~isempty(config_file)
              % Read config file
                globs.parse_config_file(config_file);
                if globs.logFile
                    globals_dev.log_progress(globs,'Read/parsed config file %s\n', {which('config.txt')});
                end
            end
            
          % Assign defaults for missing config params
            if isempty(globs.siteIDs)
                if isempty(sites)
                    globs.siteIDs = {'MCH01BR'; 'MUK01BR'; 'SQX01CF';...
                                     'MUK01SRN'; 'WPA13CRN'; 'MCH01SRN'};
                else
                    globs.siteIDs = sites;
                end
            end
            if globs.logFile
                globals_dev.log_progress(globs,'siteIDs = ');
                globals_dev.log_progress(globs,'%s', globs.siteIDs(1));
                if length(globs.siteIDs)-1
                    globals_dev.log_progress(globs,', %s', globs.siteIDs(2:end));
                end
                globals_dev.log_progress(globs,'\n');
            end
            
            globs.assign_defaults('DB', 'Mooring_COTS_Dev')
            globs.assign_defaults('av_win', 1)
            globs.assign_defaults('av_thresh', 70)
            recipients = {'dgol461@ecy.wa.gov'};
            if ~globs.logFile % Proxy for value of verbose
              % verbose==0 => running in default mode => Brandon needs to be notified of errors
              recipients{2} = 'bsac461@ecy.wa.gov';
            end
            globs.oEN = error_notification(recipients);
            if globs.logFile
                globals_dev.log_progress(globs,'Set the following globals/environment variables:\n');
                globals_dev.log_progress(globs,'%s: %s\n', {'database', globs.DB,...
                                                'SMTP Server', globs.oEN.outgoingMailServ,...
                                                'email sender', globs.oEN.mail_sender});
                globals_dev.log_progress(globs,'email recipients: %s', globs.oEN.mail_recip(1));
                if length(globs.oEN.mail_recip)-1
                    globals_dev.log_progress(globs,', %s', globs.oEN.mail_recip(2:end));
                end
                globals_dev.log_progress(globs,'\n');
                globals_dev.log_progress(globs,'%s: %g\n',...
                                   {'av_win (running average window, days)',...
                                    globs.av_win;...
                                    'av_thresh (running average threshold, consecutive samples)',...
                                    globs.av_thresh}'); % final ' is the transpose op.
            end
            
            if nargin < 2 || isempty(t_interval)
                stop = utcnow();
                globs.t_interval = [stop-14 stop];
            else
                tmp = strtok(strtok(t_interval, ']'), '[');
                [start, stop] = strtok(tmp, ' ');
                globs.t_interval = [str2double(start) str2double(stop)];
            end
            if globs.logFile
                globals_dev.log_progress(globs,'Start time set to: %s\n', {datestr(globs.t_interval(1))});
                globals_dev.log_progress(globs,'End time set to: %s\n', {datestr(globs.t_interval(2))});
            end
    
            globs.switches = struct('ascii', 1, 'plot', 1, 'delete_plot', 1, ...
                                    'ftp', 1, 'web', 1, 'exit', 1); 
            if nargin >= 3 && ~isempty(switches)
                tmp = textscan(switches, '%s %d;');
                for i=1:length(tmp{1})
                    globs.switches.(tmp{1}{i}) = globs.switches.(tmp{1}{i}) && tmp{2}(i);
                end
            end
            if globs.logFile
                globals_dev.log_progress(globs,'Switches: \n');
                globals_dev.log_progress(globs,'%s: %d\n', {'ascii', globs.switches.ascii;
                                                'plot', globs.switches.plot;
                                                'delete_plot', globs.switches.delete_plot;
                                                'ftp', globs.switches.ftp;
                                                'web', globs.switches.web;
                                                'exit', globs.switches.exit}');
            end
        end
        
        function parse_config_file(obj, filename)
          % Load data from the config file
            try
                fid = fopen(filename, 'r');
                tmp = textscan(fid, '%s %s', 'Delimiter', ':');
                fclose(fid);
                for i=1:length(tmp{1})
                    try
                        findprop(obj, tmp{1}{i});
                    catch
                        continue
                    end
                    if ischar(obj.(tmp{1}{i}))
                        obj.(tmp{1}{i}) = strtrim(tmp{2}{i});
                    elseif iscell(obj.(tmp{1}{i}))
                        obj.(tmp{1}{i}){end+1} = strtrim(tmp{2}{i});
                    elseif isfloat(obj.(tmp{1}{i}))
                        obj.(tmp{1}{i})(end+1) = str2double(tmp{2}{i});
                    else
                        throw(ME)
                    end
                end
            catch ME
                obj.oEN.notify('rt_driver_dev.globals_dev ',...
                        ['Error reading/parsing config file; '...
                         ' fatal error, quiting...'])
                obj.fatal_error = true;
            end
        end
        
        function assign_defaults(obj, propname, value)
            if isempty(obj.(propname))
                obj.(propname) = value;
            end
        end
    end
    
    methods(Static)
        function log_progress(obj, fmt, params)
            if nargin < 3
                fprintf(obj.logFile, fmt);
                fprintf(1, fmt);
            else
                fprintf(obj.logFile, fmt, params{:});
                fprintf(1, fmt, params{:});
            end
        end
        
        function out = trimPUTCD(PUTCD)
            for i=1:length(PUTCD)
                PUTCD{i} = PUTCD{i}(1:end-7);
            end
            out = PUTCD;
        end
    end
end

